#include "QtWorld.h"
#include "QtRobot.h"
#include "QtTileManager.h"
#include "QtPixmapSprite.h"
#include "QtLineSprite.h"
#include "QtTileOffsetToEffect.h"
#include "QtRotateToEffect.h"

#include "RobotMoveCommand.h"
#include "RobotTurnCommand.h"
#include "RobotSpawnCommand.h"
#include "RobotFallCommand.h"
#include "RobotHitCommand.h"
#include "TreadmillActivateCommand.h"
#include "SpinnerActivateCommand.h"
#include "CheckPointActivateCommand.h"
#include "RepairPointActivateCommand.h"
#include "PusherActivateCommand.h"
#include "LaserActivateCommand.h"
#include "RobotShootCommand.h"

QtWorld::QtWorld(QObject *parent): QGraphicsScene(parent)
{

	cellSize = 64;
	setSceneRect(0, 0, 250, 250);

	treadmill1 = (QtTreadmill*)CreateTreadmill(Direction::NORTH, 0, 1);
	treadmill2 = (QtTreadmill*)CreateTreadmill(Direction::WEST, 0, 0);
	check1 = (QtCheckPoint*)CreateCheckPoint(1, 0);
	spinner1 = (QtSpinner*)CreateSpinner(Direction::WEST, 1, 1);
	spinner2 = (QtSpinner*)CreateSpinner(Direction::EAST, 1, 2);
	repair1 = (QtRepairPoint*)CreateRepairPoint(0, 2);
	wall1 = (QtWall*)CreateWall(Direction::WEST, 0, 3);
	wall2 = (QtWall*)CreateWall(Direction::EAST, 0, 4);
	wall3 = (QtWall*)CreateWall(Direction::NORTH, 0, 5);
	wall4 = (QtWall*)CreateWall(Direction::SOUTH, 1, 5);
	pusher1 = (QtPusher*)CreatePusher(Direction::SOUTH, 1, 4);
	laser1 = (QtLaser*)CreateLaser(Direction::SOUTH, 1, 3);
	robot2 = (QtRobot*)CreateRobot("green", 0, 1);
	robot1 = (QtRobot*)CreateRobot("red", 1, 5);

	animations = 0;
	animated = false;


	// Test code om log boek samen te stellen

	BeginCommand();
	RobotMove(robot2, Direction::NORTH);
	TreadmillActivate(treadmill1);
	//RobotMove(robot1, Direction::SOUTH);
	//LaserActivate(laser1, true);
	EndCommand();

	BeginCommand();
	RobotMove(robot2, Direction::WEST);
	TreadmillActivate(treadmill2);
	//RobotMove(robot1, Direction::EAST);
	EndCommand();

	BeginCommand();
	RepairPointActivate(repair1);
	EndCommand();

	BeginCommand();
	RobotMove(robot2, Direction::SOUTH);
	RobotMove(robot1, Direction::SOUTH);
	EndCommand();

	BeginCommand();
	CheckPointActivate(check1);
	PusherActivate(pusher1);
	RobotMove(robot1, Direction::SOUTH);
	EndCommand();

	BeginCommand();
	RobotMove(robot2, Direction::SOUTH);
	EndCommand();

	BeginCommand();
	PusherActivate(pusher1);
	RobotMove(robot2, Direction::SOUTH);
	EndCommand();

	BeginCommand();
	laser1->SetLaserDestination(robot2->Position());
	LaserActivate(laser1, true);
	RobotHit(robot2);
	RobotHit(robot1);
	EndCommand();

	BeginCommand();
	RobotTurn(robot2, Direction::EAST);
	EndCommand();

	BeginCommand();
	RobotMove(robot2, Direction::EAST);
	EndCommand();

	BeginCommand();
	RobotTurn(robot2, Direction::WEST);
	SpinnerActivate(spinner2);
	EndCommand();

	BeginCommand();
	RobotMove(robot2, Direction::NORTH);
	EndCommand();

	BeginCommand();
	RobotTurn(robot2, Direction::EAST);
	SpinnerActivate(spinner1);
	EndCommand();

	BeginCommand();
	//robot->SetLaserDestination( robot1->Position() );
	robot2->SetLaserDestination( QPoint(85, 145));
	RobotShoot(robot2);
	EndCommand();

	BeginCommand();
	RobotFall(robot1);
	EndCommand();

	BeginCommand();
	RobotSpawn(robot1);
	EndCommand();


	// Speel logboek af
	Play(false);
}

QtWorld::~QtWorld()
{
}

Treadmill* QtWorld::CreateTreadmill(const Direction& direction, unsigned int cellx, unsigned int celly)
{
	QtTreadmill* treadmill = new QtTreadmill(direction);
	treadmill->SetPixmap( tileManager.Tile(*treadmill, "foreground") );
	treadmill->SetBackground( tileManager.Tile(*treadmill, "background") );
	treadmill->SetPosition(QPoint(cellx*cellSize, celly*cellSize));
	treadmill->AddToScene(this);

	QObject::connect(treadmill, SIGNAL(Finished()), this, SLOT(OnAnimationFinished()));
	QObject::connect(treadmill, SIGNAL(Started()), this, SLOT(OnAnimationStarted()));

	return treadmill;
}

Spinner* QtWorld::CreateSpinner(const Direction& direction, unsigned int cellx, unsigned int celly)
{
	QtSpinner *spinner = new QtSpinner(direction);
	spinner->SetPixmap( tileManager.Tile(*spinner, "foreground") );
	spinner->SetBackground( tileManager.Tile(*spinner, "background") );
	spinner->SetPosition(QPoint(cellx*cellSize, celly*cellSize));
	spinner->AddToScene(this);

	QObject::connect(spinner, SIGNAL(Finished()), this, SLOT(OnAnimationFinished()));
	QObject::connect(spinner, SIGNAL(Started()), this, SLOT(OnAnimationStarted()));

	return spinner;
}

RepairPoint* QtWorld::CreateRepairPoint(unsigned int cellx, unsigned int celly)
{
	QtRepairPoint *repair = new QtRepairPoint();
	repair->SetPixmap( tileManager.Tile(*repair, "foreground") );
	repair->SetBackground( tileManager.Tile(*repair, "background") );
	repair->SetPosition(QPoint(cellx*cellSize, celly*cellSize));
	repair->AddToScene(this);

	QObject::connect(repair, SIGNAL(Finished()), this, SLOT(OnAnimationFinished()));
	QObject::connect(repair, SIGNAL(Started()), this, SLOT(OnAnimationStarted()));

	return repair;
}


CheckPoint* QtWorld::CreateCheckPoint(unsigned int cellx, unsigned int celly)
{
	QtCheckPoint *checkpoint = new QtCheckPoint();
	checkpoint->SetPixmap( tileManager.Tile(*checkpoint, "foreground") );
	checkpoint->SetBackground( tileManager.Tile(*checkpoint, "background") );
	checkpoint->SetPosition(QPoint(cellx*cellSize, celly*cellSize));
	checkpoint->AddToScene(this);

	QObject::connect(checkpoint, SIGNAL(Finished()), this, SLOT(OnAnimationFinished()));
	QObject::connect(checkpoint, SIGNAL(Started()), this, SLOT(OnAnimationStarted()));

	return checkpoint;
}

Wall* QtWorld::CreateWall(const Direction& direction, unsigned int cellx, unsigned int celly)
{
	QtWall *wall = new QtWall(direction);
	wall->SetPixmap( tileManager.Tile(*wall, "foreground") );
	wall->SetBackground( tileManager.Tile(*wall, "background") );
	wall->SetPosition(QPoint(cellx*cellSize, celly*cellSize));
	wall->AddToScene(this);

	QObject::connect(wall, SIGNAL(Finished()), this, SLOT(OnAnimationFinished()));
	QObject::connect(wall, SIGNAL(Started()), this, SLOT(OnAnimationStarted()));

	return wall;
}

Pusher* QtWorld::CreatePusher(const Direction& direction, unsigned int cellx, unsigned int celly)
{
	QtPusher *pusher = new QtPusher(direction);
	pusher->SetPixmap( tileManager.Tile(*pusher, "foreground") );
	pusher->SetBackground( tileManager.Tile(*pusher, "background") );
	pusher->SetPosition(QPoint(cellx*cellSize, celly*cellSize));
	pusher->AddToScene(this);

	QObject::connect(pusher, SIGNAL(Finished()), this, SLOT(OnAnimationFinished()));
	QObject::connect(pusher, SIGNAL(Started()), this, SLOT(OnAnimationStarted()));

	return pusher;
}

Laser* QtWorld::CreateLaser(const Direction& direction, unsigned int cellx, unsigned int celly)
{
	QtLaser *laser = new QtLaser(direction);
	laser->SetPixmap( tileManager.Tile(*laser, "foreground") );
	laser->SetBackground( tileManager.Tile(*laser, "background") );
	laser->SetPosition(QPoint(cellx*cellSize, celly*cellSize));
	laser->SetLaserColor(Qt::green);
	laser->AddToScene(this);

	QObject::connect(laser, SIGNAL(Finished()), this, SLOT(OnAnimationFinished()));
	QObject::connect(laser, SIGNAL(Started()), this, SLOT(OnAnimationStarted()));

	return laser;
}


Robot* QtWorld::CreateRobot(const std::string& type, unsigned int cellx, unsigned int celly)
{
	QtRobot* robot = new QtRobot(type);
	robot->SetMovementDistance(cellSize);
	robot->SetPixmap(tileManager.Tile(*robot, "robot") );
	robot->SetPosition(QPoint(cellx*cellSize, celly*cellSize));
	robot->AddToScene(this);

	QObject::connect(robot, SIGNAL(Finished()), this, SLOT(OnAnimationFinished()));
	QObject::connect(robot, SIGNAL(Started()), this, SLOT(OnAnimationStarted()));

	return robot;
}


void QtWorld::OnAnimationStarted()
{
	animations++;
	printf("animations++ = %d\n", animations);
}

void QtWorld::OnAnimationFinished()
{
	animations--;
	printf("animations-- = %d\n", animations);

	if (animations == 0)
	{
		animated = false;

		Play(true);
	}
}



void QtWorld::Play(bool dropfirst)
{
	if (!log.Empty() && dropfirst)
		log.DropFront();

	if (!log.Empty())
	{
		animated = true;
		log.Execute();
	}
}

// Test code voor opstellen van logboek
void QtWorld::BeginCommand()
{
	commandGroup.Clear();
}

void QtWorld::EndCommand()
{
	log.AddCommand(&commandGroup);
}

void QtWorld::RobotMove(Robot* robot, const Direction& direction)
{
	RobotMoveCommand command(robot, direction);

	commandGroup.AddCommand(&command);
}

void QtWorld::RobotTurn(Robot* robot, const Direction& direction)
{
	RobotTurnCommand command(robot, direction);

	commandGroup.AddCommand(&command);
}

void QtWorld::RobotSpawn(Robot* robot)
{
	RobotSpawnCommand command(robot);

	commandGroup.AddCommand(&command);
}

void QtWorld::RobotFall(Robot* robot)
{
	RobotFallCommand command(robot);

	commandGroup.AddCommand(&command);
}

void QtWorld::RobotHit(Robot* robot)
{
	RobotHitCommand command(robot);

	commandGroup.AddCommand(&command);
}

void QtWorld::RobotShoot(Robot* robot)
{
	RobotShootCommand command(robot);

	commandGroup.AddCommand(&command);
}

void QtWorld::TreadmillActivate(Treadmill* treadmill)
{
	TreadmillActivateCommand command(treadmill);

	commandGroup.AddCommand(&command);
}

void QtWorld::SpinnerActivate(Spinner* spinner)
{
	SpinnerActivateCommand command(spinner);

	commandGroup.AddCommand(&command);
}

void QtWorld::CheckPointActivate(CheckPoint* checkpoint)
{
	CheckPointActivateCommand command(checkpoint);

	commandGroup.AddCommand(&command);
}

void QtWorld::RepairPointActivate(RepairPoint* repairpoint)
{
	RepairPointActivateCommand command(repairpoint);

	commandGroup.AddCommand(&command);
}

void QtWorld::PusherActivate(Pusher* pusher)
{
	PusherActivateCommand command(pusher);

	commandGroup.AddCommand(&command);
}

void QtWorld::LaserActivate(Laser* laser, const bool& enabled)
{
	LaserActivateCommand command(laser, enabled);

	commandGroup.AddCommand(&command);
}

// Test code
void QtWorld::mousePressEvent(QGraphicsSceneMouseEvent *e)
{
	if (!animated)
	{
		animated = true;
		robot2->SetLaserDestination( e->scenePos() );
		laser1->SetLaserDestination( e->scenePos() );
		robot2->Shoot();
	}
//	robot->MoveTo( e->scenePos() );
//    robot1->MoveTo( e->scenePos()*2 );
}

void QtWorld::keyPressEvent(QKeyEvent *e)
{
	static qreal angle = 0;

	if (animated)
		return;

	animated = true;

	if (e->key() == Qt::Key_Q)
	{
		robot2->TurnLeft();
	}
	else if (e->key() == Qt::Key_W)
	{
		robot2->TurnRight();
	}
	else if (e->key() == Qt::Key_Left)
	{
		robot2->MoveLeft();
	}
	else if (e->key() == Qt::Key_Right)
	{
		robot2->MoveRight();
	}
	else if (e->key() == Qt::Key_Up)
	{
		robot2->MoveUp();
	}
	else if (e->key() == Qt::Key_Down)
	{
		robot2->MoveDown();
	}
	else if (e->key() == Qt::Key_R)
	{
		robot2->Fall();
	}
	else if (e->key() == Qt::Key_T)
	{
		robot2->Spawn();
	}
	else if (e->key() == Qt::Key_Y)
	{
		treadmill1->Move();
		treadmill2->Move();
	}
	else if (e->key() == Qt::Key_L)
	{
		spinner1->Rotate();
	}
	else if (e->key() == Qt::Key_M)
	{
		spinner2->Rotate();
	}
	else if (e->key() == Qt::Key_O)
	{
		repair1->Reached();
	}
	else if (e->key() == Qt::Key_C)
	{
		check1->Reached();
	}
	else if (e->key() == Qt::Key_J)
	{
		pusher1->Push();
	}
	else if (e->key() == Qt::Key_H)
	{
		robot2->Hit();
	}
	else if (e->key() == Qt::Key_1)
	{
		laser1->EnableLaser();
		animated = false;
	}
	else if (e->key() == Qt::Key_2)
	{
		laser1->DisableLaser();
		animated = false;
	}
	else
	{
		animated = false;
	}

}
